import asyncio
import logging
from bilibili_api import live

logger = logging.getLogger("bilibili.client")


from bilibili_api import Credential
import os
import sys
import importlib.util
CONFIG_API_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../tools/config_api.py'))
spec = importlib.util.spec_from_file_location("config_api", CONFIG_API_PATH)
config_api = importlib.util.module_from_spec(spec)
sys.modules["config_api"] = config_api
spec.loader.exec_module(config_api)
import sys
import importlib.util
CONFIG_API_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../tools/config_api.py'))
spec = importlib.util.spec_from_file_location("config_api", CONFIG_API_PATH)
config_api = importlib.util.module_from_spec(spec)
sys.modules["config_api"] = config_api
spec.loader.exec_module(config_api)

class BiliDanmuClient:
    def __init__(self, room_id, message_callback):
        self.room_id = room_id
        self.message_callback = message_callback
        # 自动从config.yaml读取cookie
        cred = None
        self.owner_uid = None
        cookie_path = os.path.join(os.path.dirname(__file__), '../../config/config.yaml')
        use_alt = False
        config = config_api.get_config()
        bilibili_conf = config.get('bilibili', {})
        use_alt = bilibili_conf.get('use_alt_account', False)
        cookies = bilibili_conf.get('alt_cookie' if use_alt else 'cookie', {})
        sessdata = cookies.get('SESSDATA')
        bili_jct = cookies.get('bili_jct')
        dedeuserid = cookies.get('DedeUserID')
        if sessdata and bili_jct and dedeuserid:
            cred = Credential(sessdata, bili_jct, dedeuserid)
            self.owner_uid = int(dedeuserid)
        if cred:
            self.room = live.LiveDanmaku(room_id, credential=cred)
            logger.info(f"已使用{'小号' if use_alt else '主号'}cookie监听弹幕")
        else:
            self.room = live.LiveDanmaku(room_id)
            logger.warning("未检测到cookie，使用匿名身份监听弹幕")
        self.running = False

    # 初始化频率限制和队列结构
    def _init_limit_structs(self):
        from collections import defaultdict, deque
        import asyncio
        self.join_limit = None
        self.join_call_history = defaultdict(lambda: deque())
        self.user_task_queues = defaultdict(asyncio.Queue)
        self.processing_users = set()
        cookie_path = os.path.join(os.path.dirname(__file__), '../../config/config.yaml')
        default_limit = {
            'captain': {'interval_minutes': 1, 'max_calls': 3},
            'admin': {'interval_minutes': 2, 'max_calls': 3},
            'normal': {'interval_minutes': 3, 'max_calls': 2}
        }
        config = config_api.get_config()
        if config is None:
            config = {}
        bilibili = config.get('bilibili', {})
        join_limit = bilibili.get('join_limit')
        if not isinstance(join_limit, dict):
            join_limit = default_limit.copy()
            bilibili['join_limit'] = join_limit
            config['bilibili'] = bilibili
            # 递归合并写入
            config_api.save_config(config)
        else:
            # 补全缺失的角色配置
            for role, val in default_limit.items():
                if role not in join_limit or not isinstance(join_limit[role], dict):
                    join_limit[role] = val.copy()
            bilibili['join_limit'] = join_limit
            config['bilibili'] = bilibili
            config_api.save_config(config)
        self.join_limit = join_limit

    def _get_user_role(self, info):
        # 主播优先识别
        try:
            user_id = int(info[2][0])
            if self.owner_uid and user_id == self.owner_uid:
                return 'owner'
            role_flag = info[2][3]
            if role_flag == 1:
                return 'captain'
            elif role_flag == 2:
                return 'admin'
            else:
                return 'normal'
        except Exception:
            return 'normal'

    async def start_listening(self):
        import asyncio
        import time
        self._init_limit_structs()
        @self.room.on("DANMU_MSG")
        async def _on_danmaku(event):
            data = event["data"]
            if "info" in data:
                info = data["info"]
            else:
                info = data
            user_id = info[2][0]
            username = info[2][1]
            text = info[1]
            role = self._get_user_role(info)
            await self.user_task_queues[(user_id, role)].put((user_id, username, text, info))
            if (user_id, role) not in self.processing_users:
                self.processing_users.add((user_id, role))
                asyncio.create_task(self._process_user_queue(user_id, role))

        @self.room.on("DISCONNECT")
        async def _on_disconnect(event):
            logger.warning(f"直播间 {self.room_id} 连接断开，尝试自动重连...")
            self.running = False
            # 延迟重连，防止频繁重试
            await asyncio.sleep(5)
            try:
                await self.room.connect()
                self.running = True
                logger.info(f"重连成功，已恢复监听直播间 {self.room_id}")
            except Exception as e:
                logger.error(f"重连失败: {e}")

        retry_count = 0
        max_retries = 15
        while True:
            try:
                await self.room.connect()
                self.running = True
                logger.info(f"成功连接到直播间 {self.room_id}")
                break
            except Exception as e:
                retry_count += 1
                if retry_count >= max_retries:
                    logger.error(f"弹幕连接连续失败{max_retries}次，自动停止主程序！")
                    import sys
                    sys.exit(1)
                logger.error(f"弹幕连接失败: {e}，3秒后重试...（第{retry_count}次）")
                await asyncio.sleep(3)

    async def _process_user_queue(self, user_id, role):
        import time
        import asyncio
        queue = self.user_task_queues[(user_id, role)]
        # 获取自定义限流回复
        config = config_api.get_config()
        limit_reply = None
        try:
            limit_reply = config.get('punish_reply', {}).get('limit', None)
        except Exception:
            limit_reply = None
        while not queue.empty():
            user_id, username, text, info = await queue.get()
            now = time.time()
            allow = True
            # owner（主播）无限制，且优先AI问答
            if role != 'owner':
                if self.join_limit and role in self.join_limit:
                    interval = self.join_limit[role].get('interval_minutes', 5) * 60
                    max_calls = self.join_limit[role].get('max_calls', 1)
                    history = self.join_call_history[(user_id, role)]
                    while history and now - history[0] > interval:
                        history.popleft()
                    if len(history) >= max_calls:
                        allow = False
            if allow:
                if role != 'owner' and self.join_limit and role in self.join_limit:
                    self.join_call_history[(user_id, role)].append(now)
                logger.info(f"[弹幕] {username}({role}): {text}")
                # 主播owner弹幕优先处理，可在此加AI优先权逻辑（已默认优先）
                await self.message_callback(user_id, username, text)
            else:
                logger.info(f"[弹幕限流] {username}({role}) 触发调用频率限制，忽略本次弹幕: {text}")
                # 自动@相关人并发送自定义回复
                if limit_reply:
                    try:
                        from core.bilibili.danmaku_sender import DanmakuSender
                        if not hasattr(self, '_danmu_sender') or self._danmu_sender is None:
                            self._danmu_sender = DanmakuSender(self.room_id)
                        reply_text = f"@{username}({user_id}) {limit_reply}"
                        asyncio.create_task(self._danmu_sender.send(reply_text))
                    except Exception as e:
                        logger.warning(f"自动发送限流自定义回复失败: {e}")
            await asyncio.sleep(0)
        self.processing_users.discard((user_id, role))

    async def stop_listening(self):
        if self.running:
            await self.room.disconnect()
            self.running = False
            logger.info("弹幕监听已停止")